package fr.lip6.move.care.sdmaker.jvmmodel;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
import fr.lip6.move.care.sdmaker.jvmmodel.CompileResult;
import fr.lip6.move.care.sdmaker.jvmmodel.SDMakerJvmModelUtils;
import fr.lip6.move.care.sdmaker.sDMaker.Alt;
import fr.lip6.move.care.sdmaker.sDMaker.Call;
import fr.lip6.move.care.sdmaker.sDMaker.CombinableElement;
import fr.lip6.move.care.sdmaker.sDMaker.Declaration;
import fr.lip6.move.care.sdmaker.sDMaker.Diagram;
import fr.lip6.move.care.sdmaker.sDMaker.Element;
import fr.lip6.move.care.sdmaker.sDMaker.Lifeline;
import fr.lip6.move.care.sdmaker.sDMaker.Loop;
import fr.lip6.move.care.sdmaker.sDMaker.Opt;
import fr.lip6.move.care.sdmaker.sDMaker.SDMakerModel;
import java.util.ArrayList;
import java.util.Arrays;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtext.common.types.JvmFormalParameter;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmMember;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable;
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer;
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor;
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor.IPostIndexingInitializing;
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder;
import org.eclipse.xtext.xbase.lib.IteratorExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;

/**
 * <p>Infers a JVM model from the source model.</p>
 * 
 * <p>The JVM model should contain all elements that would appear in the Java code
 * which is generated from the source model. Other models link against the JVM model rather than the source model.</p>
 */
@SuppressWarnings("all")
public class SDMakerJvmModelInferrer extends AbstractModelInferrer {
  /**
   * convenience API to build and initialize JVM types and their members.
   */
  @Inject
  private JvmTypesBuilder _jvmTypesBuilder;
  
  /**
   * The dispatch method {@code infer} is called for each instance of the
   * given element's type that is contained in a resource.
   * 
   * @param element
   *            the model to create one or more
   *            {@link org.eclipse.xtext.common.types.JvmDeclaredType declared
   *            types} from.
   * @param acceptor
   *            each created
   *            {@link org.eclipse.xtext.common.types.JvmDeclaredType type}
   *            without a container should be passed to the acceptor in order
   *            get attached to the current resource. The acceptor's
   *            {@link IJvmDeclaredTypeAcceptor#accept(org.eclipse.xtext.common.types.JvmDeclaredType)
   *            accept(..)} method takes the constructed empty type for the
   *            pre-indexing phase. This one is further initialized in the
   *            indexing phase using the closure you pass to the returned
   *            {@link org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor.IPostIndexingInitializing#initializeLater(org.eclipse.xtext.xbase.lib.Procedures.Procedure1)
   *            initializeLater(..)}.
   * @param isPreIndexingPhase
   *            whether the method is called in a pre-indexing phase, i.e.
   *            when the global index is not yet fully updated. You must not
   *            rely on linking using the index if isPreIndexingPhase is
   *            <code>true</code>.
   */
  private int i;
  
  protected void _infer(final SDMakerModel model, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) {
    boolean _and = false;
    boolean _notEquals = (!Objects.equal(model, null));
    if (!_notEquals) {
      _and = false;
    } else {
      EList<Diagram> _diagrams = model.getDiagrams();
      int _size = _diagrams.size();
      boolean _greaterThan = (_size > 0);
      _and = (_notEquals && _greaterThan);
    }
    if (_and) {
      this.i = 0;
      this.findAllModelTypes(model);
      this.compileInterfaces(model, acceptor, isPreIndexingPhase);
      EList<Diagram> _diagrams_1 = model.getDiagrams();
      for (final Diagram d : _diagrams_1) {
        this.compileCare(d, acceptor, isPreIndexingPhase);
      }
    }
  }
  
  private ArrayList<String> types;
  
  public void findAllModelTypes(final SDMakerModel model) {
    Boolean alreadySeenThisType = Boolean.valueOf(false);
    ArrayList<String> _arrayList = new ArrayList<String>();
    this.types = _arrayList;
    EList<Diagram> _diagrams = model.getDiagrams();
    for (final Diagram d : _diagrams) {
      EList<Element> _elements = d.getElements();
      for (final Element elt : _elements) {
        boolean _and = false;
        if (!(elt instanceof Lifeline)) {
          _and = false;
        } else {
          String _kind = ((Lifeline) elt).getKind();
          int _compareTo = _kind.compareTo("Object");
          boolean _equals = (_compareTo == 0);
          _and = ((elt instanceof Lifeline) && _equals);
        }
        if (_and) {
          Lifeline obj = ((Lifeline) elt);
          alreadySeenThisType = Boolean.valueOf(false);
          for (final String type : this.types) {
            String _type = obj.getType();
            int _compareTo_1 = _type.compareTo(type);
            boolean _equals_1 = (_compareTo_1 == 0);
            if (_equals_1) {
              alreadySeenThisType = Boolean.valueOf(true);
            }
          }
          boolean _equals_2 = ((alreadySeenThisType).booleanValue() == false);
          if (_equals_2) {
            String _type_1 = obj.getType();
            this.types.add(_type_1);
          }
        }
      }
    }
  }
  
  public void compileInterfaces(final SDMakerModel model, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) {
    for (final String type : this.types) {
      JvmGenericType _interface = this._jvmTypesBuilder.toInterface(model, type, null);
      IPostIndexingInitializing<JvmGenericType> _accept = acceptor.<JvmGenericType>accept(_interface);
      final Procedure1<JvmGenericType> _function = new Procedure1<JvmGenericType>() {
          public void apply(final JvmGenericType it) {
            TreeIterator<EObject> _eAllContents = model.eAllContents();
            Iterable<EObject> _iterable = IteratorExtensions.<EObject>toIterable(_eAllContents);
            Iterable<Declaration> _filter = Iterables.<Declaration>filter(_iterable, Declaration.class);
            for (final Declaration elt : _filter) {
              if ((elt instanceof Declaration)) {
                Declaration dcl = ((Declaration) elt);
                String _typeOwner = dcl.getTypeOwner();
                int _compareTo = _typeOwner.compareTo(type);
                boolean _equals = (_compareTo == 0);
                if (_equals) {
                  EList<JvmMember> _members = it.getMembers();
                  String _name = dcl.getName();
                  JvmTypeReference _returnType = dcl.getReturnType();
                  final Procedure1<JvmOperation> _function = new Procedure1<JvmOperation>() {
                      public void apply(final JvmOperation it) {
                        String _documentation = SDMakerJvmModelInferrer.this._jvmTypesBuilder.getDocumentation(((Declaration) elt));
                        SDMakerJvmModelInferrer.this._jvmTypesBuilder.setDocumentation(it, _documentation);
                        EList<JvmFormalParameter> _params = ((Declaration) elt).getParams();
                        for (final JvmFormalParameter p : _params) {
                          EList<JvmFormalParameter> _parameters = it.getParameters();
                          String _name = p.getName();
                          JvmTypeReference _parameterType = p.getParameterType();
                          JvmFormalParameter _parameter = SDMakerJvmModelInferrer.this._jvmTypesBuilder.toParameter(p, _name, _parameterType);
                          SDMakerJvmModelInferrer.this._jvmTypesBuilder.<JvmFormalParameter>operator_add(_parameters, _parameter);
                        }
                        it.setAbstract(true);
                      }
                    };
                  JvmOperation _method = SDMakerJvmModelInferrer.this._jvmTypesBuilder.toMethod(dcl, _name, _returnType, _function);
                  SDMakerJvmModelInferrer.this._jvmTypesBuilder.<JvmOperation>operator_add(_members, _method);
                }
              }
            }
          }
        };
      _accept.initializeLater(_function);
    }
  }
  
  public void compileCare(final Diagram d, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) {
    String _name = d.getName();
    JvmGenericType _class = this._jvmTypesBuilder.toClass(d, _name);
    IPostIndexingInitializing<JvmGenericType> _accept = acceptor.<JvmGenericType>accept(_class);
    final Procedure1<JvmGenericType> _function = new Procedure1<JvmGenericType>() {
        public void apply(final JvmGenericType it) {
          String _documentation = SDMakerJvmModelInferrer.this._jvmTypesBuilder.getDocumentation(d);
          SDMakerJvmModelInferrer.this._jvmTypesBuilder.setDocumentation(it, _documentation);
          EList<JvmMember> _members = it.getMembers();
          String _name = d.getName();
          String _plus = ("create_" + _name);
          JvmTypeReference _newTypeRef = SDMakerJvmModelInferrer.this._jvmTypesBuilder.newTypeRef(d, "Main");
          final Procedure1<JvmOperation> _function = new Procedure1<JvmOperation>() {
              public void apply(final JvmOperation it) {
                String _documentation = SDMakerJvmModelInferrer.this._jvmTypesBuilder.getDocumentation(d);
                SDMakerJvmModelInferrer.this._jvmTypesBuilder.setDocumentation(it, _documentation);
                final Procedure1<ITreeAppendable> _function = new Procedure1<ITreeAppendable>() {
                    public void apply(final ITreeAppendable it) {
                      StringConcatenation _builder = new StringConcatenation();
                      _builder.append("int i= 0;");
                      _builder.newLine();
                      _builder.append("ArrayList<Actor> actors= new ArrayList<Actor>();");
                      _builder.newLine();
                      it.append(_builder);
                      ArrayList<CompileResult> _arrayList = new ArrayList<CompileResult>();
                      ArrayList<CompileResult> allCompRes = _arrayList;
                      EList<Element> _elements = d.getElements();
                      for (final Element elt : _elements) {
                        {
                          CompileResult compRes = SDMakerJvmModelInferrer.this.compileElt(elt);
                          allCompRes.add(compRes);
                          CharSequence _charSequenceResult = compRes.getCharSequenceResult();
                          it.append(_charSequenceResult);
                        }
                      }
                      int _plus = (SDMakerJvmModelInferrer.this.i + 1);
                      int _i = SDMakerJvmModelInferrer.this.i = _plus;
                      String mainID = ("entry_point_id" + Integer.valueOf(_i));
                      StringConcatenation _builder_1 = new StringConcatenation();
                      _builder_1.newLine();
                      _builder_1.append("ArrayList<Block> ");
                      _builder_1.append(mainID, "");
                      _builder_1.append(" = new ArrayList<Block>();");
                      _builder_1.newLineIfNotEmpty();
                      it.append(_builder_1);
                      CompileResult compRes = CompileResult.getEmptyResult();
                      Boolean found = Boolean.valueOf(false);
                      int i = 0;
                      boolean _and = false;
                      boolean _equals = ((found).booleanValue() == false);
                      if (!_equals) {
                        _and = false;
                      } else {
                        int _size = allCompRes.size();
                        boolean _lessThan = (i < _size);
                        _and = (_equals && _lessThan);
                      }
                      boolean _while = _and;
                      while (_while) {
                        {
                          found = Boolean.valueOf(true);
                          StringConcatenation _builder_2 = new StringConcatenation();
                          _builder_2.append("HELLO_WORLD->found=");
                          _builder_2.append(found, "");
                          _builder_2.append(", i=");
                          _builder_2.append(i, "");
                          _builder_2.append(", i < allCompRes.size()=");
                          int _size_1 = allCompRes.size();
                          boolean _lessThan_1 = (i < _size_1);
                          _builder_2.append(_lessThan_1, "");
                          _builder_2.append("    THE_AND_IS");
                          boolean _and_1 = false;
                          boolean _equals_1 = ((found).booleanValue() == false);
                          if (!_equals_1) {
                            _and_1 = false;
                          } else {
                            int _size_2 = allCompRes.size();
                            boolean _lessThan_2 = (i < _size_2);
                            _and_1 = (_equals_1 && _lessThan_2);
                          }
                          _builder_2.append(_and_1, "");
                          it.append(_builder_2);
                        }
                        boolean _and_1 = false;
                        boolean _equals_1 = ((found).booleanValue() == false);
                        if (!_equals_1) {
                          _and_1 = false;
                        } else {
                          int _size_1 = allCompRes.size();
                          boolean _lessThan_1 = (i < _size_1);
                          _and_1 = (_equals_1 && _lessThan_1);
                        }
                        _while = _and_1;
                      }
                      StringConcatenation _builder_2 = new StringConcatenation();
                      _builder_2.append("return new Main(");
                      _builder_2.append(mainID, "");
                      _builder_2.append(", actors, 200);");
                      it.append(_builder_2);
                    }
                  };
                SDMakerJvmModelInferrer.this._jvmTypesBuilder.setBody(it, _function);
              }
            };
          JvmOperation _method = SDMakerJvmModelInferrer.this._jvmTypesBuilder.toMethod(d, _plus, _newTypeRef, _function);
          SDMakerJvmModelInferrer.this._jvmTypesBuilder.<JvmOperation>operator_add(_members, _method);
        }
      };
    _accept.initializeLater(_function);
  }
  
  /**
   * Methode d'aiguillage
   */
  public CompileResult compileElt(final Element elt) {
    CompileResult _switchResult = null;
    boolean _matched = false;
    if (!_matched) {
      if (elt instanceof Lifeline) {
        final Lifeline _lifeline = (Lifeline)elt;
        _matched=true;
        CompileResult _xifexpression = null;
        String _kind = ((Lifeline) _lifeline).getKind();
        int _compareTo = _kind.compareTo("Actor");
        boolean _equals = (_compareTo == 0);
        if (_equals) {
          CompileResult _compileActor = this.compileActor(_lifeline);
          _xifexpression = _compileActor;
        } else {
          CompileResult _compileObject = this.compileObject(_lifeline);
          _xifexpression = _compileObject;
        }
        _switchResult = _xifexpression;
      }
    }
    if (!_matched) {
      if (elt instanceof Call) {
        final Call _call = (Call)elt;
        _matched=true;
        CompileResult _compileCall = this.compileCall(_call);
        _switchResult = _compileCall;
      }
    }
    if (!_matched) {
      if (elt instanceof Alt) {
        final Alt _alt = (Alt)elt;
        _matched=true;
        CompileResult _compileAlt = this.compileAlt(_alt);
        _switchResult = _compileAlt;
      }
    }
    if (!_matched) {
      if (elt instanceof Loop) {
        final Loop _loop = (Loop)elt;
        _matched=true;
        CompileResult _compileLoop = this.compileLoop(_loop);
        _switchResult = _compileLoop;
      }
    }
    if (!_matched) {
      if (elt instanceof Opt) {
        final Opt _opt = (Opt)elt;
        _matched=true;
        CompileResult _compileOpt = this.compileOpt(_opt);
        _switchResult = _compileOpt;
      }
    }
    if (!_matched) {
      CompileResult _emptyResult = CompileResult.getEmptyResult();
      _switchResult = _emptyResult;
    }
    return _switchResult;
  }
  
  /**
   * Compilation des acteurs
   */
  public CompileResult compileActor(final Lifeline actor) {
    StringConcatenation _builder = new StringConcatenation();
    _builder.append("                                  ");
    _builder.newLine();
    _builder.append("ObjectClass ");
    String _name = actor.getName();
    _builder.append(_name, "");
    _builder.append("=new ObjectClass(\"");
    String _name_1 = actor.getName();
    _builder.append(_name_1, "");
    _builder.append("\");");
    _builder.newLineIfNotEmpty();
    _builder.append("Actor ");
    String _name_2 = actor.getName();
    _builder.append(_name_2, "");
    _builder.append(" = new Actor(\"");
    String _name_3 = actor.getName();
    _builder.append(_name_3, "");
    _builder.append("\", ");
    String _name_4 = actor.getName();
    _builder.append(_name_4, "");
    _builder.append(");   ");
    _builder.newLineIfNotEmpty();
    _builder.append("actors.add(");
    String _name_5 = actor.getName();
    _builder.append(_name_5, "");
    _builder.append(");                                                 ");
    _builder.newLineIfNotEmpty();
    CharSequence charSequenceResult = _builder;
    CompileResult _compileResult = new CompileResult();
    CompileResult _setCharSequenceResult = _compileResult.setCharSequenceResult(charSequenceResult);
    String _name_6 = actor.getName();
    CompileResult _setEltID = _setCharSequenceResult.setEltID(_name_6);
    return _setEltID.setEltKind("Actor");
  }
  
  /**
   * Compilation des objets
   */
  public CompileResult compileObject(final Lifeline obj) {
    StringConcatenation _builder = new StringConcatenation();
    CharSequence charSequenceResult = _builder;
    CompileResult _compileResult = new CompileResult();
    CompileResult _setCharSequenceResult = _compileResult.setCharSequenceResult(charSequenceResult);
    String _name = obj.getName();
    CompileResult _setEltID = _setCharSequenceResult.setEltID(_name);
    return _setEltID.setEltKind("Object");
  }
  
  /**
   * Compilation des appels de methode
   */
  public CompileResult compileCall(final Call call) {
    ArrayList<String> _arrayList = new ArrayList<String>();
    ArrayList<String> nestedEltIDs = _arrayList;
    CompileResult compRes = null;
    String _name = call.getName();
    String _plus = (_name + "_id");
    int _plus_1 = (this.i + 1);
    int _i = this.i = _plus_1;
    String callID = (_plus + Integer.valueOf(_i));
    StringConcatenation _builder = new StringConcatenation();
    _builder.newLine();
    {
      EList<CombinableElement> _nested_calls = call.getNested_calls();
      int _size = _nested_calls.size();
      boolean _equals = (_size == 0);
      if (_equals) {
        _builder.append("Call ");
        _builder.append(callID, "");
        _builder.append(" = new Call(new Statement(\"S\" + i++,");
        String _caller = call.getCaller();
        _builder.append(_caller, "");
        _builder.append(",new Method(\"");
        String _name_1 = call.getName();
        _builder.append(_name_1, "");
        _builder.append("\",new ArrayList<ObjectInstance>(),");
        String _called = call.getCalled();
        _builder.append(_called, "");
        _builder.append("),");
        String _called_1 = call.getCalled();
        _builder.append(_called_1, "");
        _builder.append("));");
        _builder.newLineIfNotEmpty();
      } else {
        _builder.append("/* NESTED CALL: ");
        _builder.append(callID, "");
        _builder.append(" */");
        _builder.newLineIfNotEmpty();
        _builder.append("BlockList bloc_");
        _builder.append(callID, "");
        _builder.append("= new BlockList();");
        _builder.newLineIfNotEmpty();
        {
          EList<CombinableElement> _nested_calls_1 = call.getNested_calls();
          for(final CombinableElement elt : _nested_calls_1) {
            {
              boolean _not = (!(elt instanceof Declaration));
              if (_not) {
                CompileResult _compileElt = this.compileElt(elt);
                CompileResult _compRes = compRes = _compileElt;
                CharSequence _nullExp = SDMakerJvmModelUtils.toNullExp(_compRes);
                _builder.append(_nullExp, "");
                _builder.newLineIfNotEmpty();
                String _eltID = compRes.getEltID();
                boolean _add = nestedEltIDs.add(_eltID);
                CharSequence _nullExp_1 = SDMakerJvmModelUtils.toNullExp(Boolean.valueOf(_add));
                _builder.append(_nullExp_1, "");
                _builder.newLineIfNotEmpty();
                CharSequence _charSequenceResult = compRes.getCharSequenceResult();
                _builder.append(_charSequenceResult, "");
                _builder.newLineIfNotEmpty();
              }
            }
          }
        }
        _builder.newLine();
        _builder.append("/* add(s) for ");
        _builder.append(callID, "");
        _builder.append(" */");
        _builder.newLineIfNotEmpty();
        {
          for(final String eltID : nestedEltIDs) {
            _builder.append("bloc_");
            _builder.append(callID, "");
            _builder.append(".add(");
            _builder.append(eltID, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
          }
        }
        _builder.newLine();
        _builder.append("Call ");
        _builder.append(callID, "");
        _builder.append(" = new Call(new Statement(\"S\" + i++,");
        String _caller_1 = call.getCaller();
        _builder.append(_caller_1, "");
        _builder.append(",new Method(\"");
        String _name_2 = call.getName();
        _builder.append(_name_2, "");
        _builder.append("\",new ArrayList<ObjectInstance>(),");
        String _called_2 = call.getCalled();
        _builder.append(_called_2, "");
        _builder.append("),");
        String _called_3 = call.getCalled();
        _builder.append(_called_3, "");
        _builder.append("), bloc_");
        String _name_3 = call.getName();
        _builder.append(_name_3, "");
        _builder.append(");");
        _builder.newLineIfNotEmpty();
      }
    }
    CharSequence charSequenceResult = _builder;
    CompileResult _compileResult = new CompileResult();
    CompileResult _setCharSequenceResult = _compileResult.setCharSequenceResult(charSequenceResult);
    CompileResult _setEltID = _setCharSequenceResult.setEltID(callID);
    return _setEltID.setEltKind("Call");
  }
  
  /**
   * Compilation des alternatives
   */
  public CompileResult compileAlt(final Alt alt) {
    ArrayList<String> _arrayList = new ArrayList<String>();
    ArrayList<String> conseqNestedEltIDs = _arrayList;
    ArrayList<String> _arrayList_1 = new ArrayList<String>();
    ArrayList<String> alterNestedEltIDs = _arrayList_1;
    CompileResult compRes = null;
    int _plus = (this.i + 1);
    int _i = this.i = _plus;
    String altID = ("alt_id" + Integer.valueOf(_i));
    StringConcatenation _builder = new StringConcatenation();
    _builder.newLine();
    _builder.append("/* ALTERNATIVE: ");
    _builder.append(altID, "");
    _builder.append(" */");
    _builder.newLineIfNotEmpty();
    _builder.append("BlockList bloc_");
    _builder.append(altID, "");
    _builder.append("_conseq = new BloclList();");
    _builder.newLineIfNotEmpty();
    {
      EList<CombinableElement> _conseq = alt.getConseq();
      for(final CombinableElement elt : _conseq) {
        {
          boolean _not = (!(elt instanceof Declaration));
          if (_not) {
            CompileResult _compileElt = this.compileElt(elt);
            CompileResult _compRes = compRes = _compileElt;
            CharSequence _nullExp = SDMakerJvmModelUtils.toNullExp(_compRes);
            _builder.append(_nullExp, "");
            _builder.newLineIfNotEmpty();
            String _eltID = compRes.getEltID();
            boolean _add = conseqNestedEltIDs.add(_eltID);
            CharSequence _nullExp_1 = SDMakerJvmModelUtils.toNullExp(Boolean.valueOf(_add));
            _builder.append(_nullExp_1, "");
            _builder.newLineIfNotEmpty();
            CharSequence _charSequenceResult = compRes.getCharSequenceResult();
            _builder.append(_charSequenceResult, "");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    {
      int _size = conseqNestedEltIDs.size();
      boolean _greaterThan = (_size > 0);
      if (_greaterThan) {
        _builder.append("// add(s) for bloc_");
        _builder.append(altID, "");
        _builder.append("_conseq");
        _builder.newLineIfNotEmpty();
        {
          for(final String eltID : conseqNestedEltIDs) {
            _builder.append("bloc_");
            _builder.append(altID, "");
            _builder.append("_conseq.add(");
            _builder.append(eltID, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    _builder.append("BlockList bloc_");
    _builder.append(altID, "");
    _builder.append("_alter = new BloclList();");
    _builder.newLineIfNotEmpty();
    {
      EList<CombinableElement> _alter = alt.getAlter();
      for(final CombinableElement elt_1 : _alter) {
        {
          boolean _not_1 = (!(elt_1 instanceof Declaration));
          if (_not_1) {
            CompileResult _compileElt_1 = this.compileElt(elt_1);
            CompileResult _compRes_1 = compRes = _compileElt_1;
            CharSequence _nullExp_2 = SDMakerJvmModelUtils.toNullExp(_compRes_1);
            _builder.append(_nullExp_2, "");
            _builder.newLineIfNotEmpty();
            String _eltID_1 = compRes.getEltID();
            boolean _add_1 = alterNestedEltIDs.add(_eltID_1);
            CharSequence _nullExp_3 = SDMakerJvmModelUtils.toNullExp(Boolean.valueOf(_add_1));
            _builder.append(_nullExp_3, "");
            _builder.newLineIfNotEmpty();
            CharSequence _charSequenceResult_1 = compRes.getCharSequenceResult();
            _builder.append(_charSequenceResult_1, "");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    {
      int _size_1 = alterNestedEltIDs.size();
      boolean _greaterThan_1 = (_size_1 > 0);
      if (_greaterThan_1) {
        _builder.append("// add(s) for bloc_");
        _builder.append(altID, "");
        _builder.append("_alter");
        _builder.newLineIfNotEmpty();
        {
          for(final String eltID_1 : alterNestedEltIDs) {
            _builder.append("bloc_");
            _builder.append(altID, "");
            _builder.append("_alter.add(");
            _builder.append(eltID_1, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    _builder.append("// adds for ");
    _builder.append(altID, "");
    _builder.newLineIfNotEmpty();
    _builder.append("Alt ");
    _builder.append(altID, "");
    _builder.append("= new Alt();");
    _builder.newLineIfNotEmpty();
    _builder.append(altID, "");
    _builder.append(".add(bloc_");
    _builder.append(altID, "");
    _builder.append("_conseq);");
    _builder.newLineIfNotEmpty();
    _builder.append(altID, "");
    _builder.append(".add(bloc_");
    _builder.append(altID, "");
    _builder.append("_alter);");
    _builder.newLineIfNotEmpty();
    CharSequence charSequenceResult = _builder;
    CompileResult _compileResult = new CompileResult();
    CompileResult _setCharSequenceResult = _compileResult.setCharSequenceResult(charSequenceResult);
    CompileResult _setEltID = _setCharSequenceResult.setEltID(altID);
    return _setEltID.setEltKind("Alt");
  }
  
  /**
   * Compilation des boucles
   */
  public CompileResult compileLoop(final Loop loop) {
    ArrayList<String> _arrayList = new ArrayList<String>();
    ArrayList<String> nestedEltIDs = _arrayList;
    CompileResult compRes = null;
    int _plus = (this.i + 1);
    int _i = this.i = _plus;
    String loopID = ("loop_id" + Integer.valueOf(_i));
    StringConcatenation _builder = new StringConcatenation();
    _builder.newLine();
    _builder.append("/* LOOP: ");
    _builder.append(loopID, "");
    _builder.append(" */");
    _builder.newLineIfNotEmpty();
    _builder.append("BlockList bloc_");
    _builder.append(loopID, "");
    _builder.append(" = new BloclList();");
    _builder.newLineIfNotEmpty();
    {
      EList<CombinableElement> _body = loop.getBody();
      for(final CombinableElement elt : _body) {
        {
          boolean _not = (!(elt instanceof Declaration));
          if (_not) {
            CompileResult _compileElt = this.compileElt(elt);
            CompileResult _compRes = compRes = _compileElt;
            CharSequence _nullExp = SDMakerJvmModelUtils.toNullExp(_compRes);
            _builder.append(_nullExp, "");
            _builder.newLineIfNotEmpty();
            String _eltID = compRes.getEltID();
            boolean _add = nestedEltIDs.add(_eltID);
            CharSequence _nullExp_1 = SDMakerJvmModelUtils.toNullExp(Boolean.valueOf(_add));
            _builder.append(_nullExp_1, "");
            _builder.newLineIfNotEmpty();
            CharSequence _charSequenceResult = compRes.getCharSequenceResult();
            _builder.append(_charSequenceResult, "");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    {
      int _size = nestedEltIDs.size();
      boolean _greaterThan = (_size > 0);
      if (_greaterThan) {
        _builder.append("//add(s) for ");
        _builder.append(loopID, "");
        _builder.newLineIfNotEmpty();
        {
          for(final String eltID : nestedEltIDs) {
            _builder.append("bloc_");
            _builder.append(loopID, "");
            _builder.append(".add(");
            _builder.append(eltID, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.append("Loop ");
    _builder.append(loopID, "");
    _builder.append(" = new Loop(bloc_");
    _builder.append(loopID, "");
    _builder.append(");");
    _builder.newLineIfNotEmpty();
    CharSequence charSequenceResult = _builder;
    CompileResult _compileResult = new CompileResult();
    CompileResult _setCharSequenceResult = _compileResult.setCharSequenceResult(charSequenceResult);
    CompileResult _setEltID = _setCharSequenceResult.setEltID(loopID);
    return _setEltID.setEltKind("Loop");
  }
  
  /**
   * Compilation des options
   */
  public CompileResult compileOpt(final Opt opt) {
    ArrayList<String> _arrayList = new ArrayList<String>();
    ArrayList<String> nestedEltIDs = _arrayList;
    CompileResult compRes = null;
    int _plus = (this.i + 1);
    int _i = this.i = _plus;
    String optID = ("opt_id" + Integer.valueOf(_i));
    StringConcatenation _builder = new StringConcatenation();
    _builder.newLine();
    _builder.append("/* OPTION: ");
    _builder.append(optID, "");
    _builder.append(" */");
    _builder.newLineIfNotEmpty();
    _builder.append("BlockList bloc_");
    _builder.append(optID, "");
    _builder.append(" = new BloclList();");
    _builder.newLineIfNotEmpty();
    {
      EList<CombinableElement> _opts = opt.getOpts();
      for(final CombinableElement elt : _opts) {
        {
          boolean _not = (!(elt instanceof Declaration));
          if (_not) {
            CompileResult _compileElt = this.compileElt(elt);
            CompileResult _compRes = compRes = _compileElt;
            CharSequence _nullExp = SDMakerJvmModelUtils.toNullExp(_compRes);
            _builder.append(_nullExp, "");
            _builder.newLineIfNotEmpty();
            String _eltID = compRes.getEltID();
            boolean _add = nestedEltIDs.add(_eltID);
            CharSequence _nullExp_1 = SDMakerJvmModelUtils.toNullExp(Boolean.valueOf(_add));
            _builder.append(_nullExp_1, "");
            _builder.newLineIfNotEmpty();
            CharSequence _charSequenceResult = compRes.getCharSequenceResult();
            _builder.append(_charSequenceResult, "");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    {
      int _size = nestedEltIDs.size();
      boolean _greaterThan = (_size > 0);
      if (_greaterThan) {
        _builder.append("//add(s) for ");
        _builder.append(optID, "");
        _builder.newLineIfNotEmpty();
        {
          for(final String eltID : nestedEltIDs) {
            _builder.append("bloc_");
            _builder.append(optID, "");
            _builder.append(".add(");
            _builder.append(eltID, "");
            _builder.append(");");
            _builder.newLineIfNotEmpty();
          }
        }
      }
    }
    _builder.newLine();
    _builder.append("Opt ");
    _builder.append(optID, "");
    _builder.append(" = new Opt(bloc_");
    _builder.append(optID, "");
    _builder.append(");");
    _builder.newLineIfNotEmpty();
    CharSequence charSequenceResult = _builder;
    CompileResult _compileResult = new CompileResult();
    CompileResult _setCharSequenceResult = _compileResult.setCharSequenceResult(charSequenceResult);
    CompileResult _setEltID = _setCharSequenceResult.setEltID(optID);
    return _setEltID.setEltKind("Opt");
  }
  
  public CompileResult findEntryPoint(final ArrayList<CompileResult> allResult, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase, final Diagram d) {
    CompileResult compRes = CompileResult.getEmptyResult();
    Boolean found = Boolean.valueOf(false);
    int i = 0;
    boolean _and = false;
    boolean _equals = ((found).booleanValue() == false);
    if (!_equals) {
      _and = false;
    } else {
      int _size = allResult.size();
      boolean _lessThan = (i < _size);
      _and = (_equals && _lessThan);
    }
    boolean _while = _and;
    while (_while) {
      {
        boolean _or = false;
        boolean _or_1 = false;
        boolean _or_2 = false;
        CompileResult _get = allResult.get(i);
        String _eltKind = _get.getEltKind();
        int _compareTo = _eltKind.compareTo("Call");
        boolean _equals_1 = (_compareTo == 0);
        if (_equals_1) {
          _or_2 = true;
        } else {
          CompileResult _get_1 = allResult.get(i);
          String _eltKind_1 = _get_1.getEltKind();
          int _compareTo_1 = _eltKind_1.compareTo("Alt");
          boolean _equals_2 = (_compareTo_1 == 0);
          _or_2 = (_equals_1 || _equals_2);
        }
        if (_or_2) {
          _or_1 = true;
        } else {
          CompileResult _get_2 = allResult.get(i);
          String _eltKind_2 = _get_2.getEltKind();
          int _compareTo_2 = _eltKind_2.compareTo("Loop");
          boolean _equals_3 = (_compareTo_2 == 0);
          _or_1 = (_or_2 || _equals_3);
        }
        if (_or_1) {
          _or = true;
        } else {
          CompileResult _get_3 = allResult.get(i);
          String _eltKind_3 = _get_3.getEltKind();
          int _compareTo_3 = _eltKind_3.compareTo("Opt");
          boolean _equals_4 = (_compareTo_3 == 0);
          _or = (_or_1 || _equals_4);
        }
        if (_or) {
          CompileResult _get_4 = allResult.get(i);
          compRes = _get_4;
          found = Boolean.valueOf(true);
        }
        int _plus = (i + 1);
        i = _plus;
      }
      boolean _and_1 = false;
      boolean _equals_1 = ((found).booleanValue() == false);
      if (!_equals_1) {
        _and_1 = false;
      } else {
        int _size_1 = allResult.size();
        boolean _lessThan_1 = (i < _size_1);
        _and_1 = (_equals_1 && _lessThan_1);
      }
      _while = _and_1;
    }
    return compRes;
  }
  
  public void infer(final EObject model, final IJvmDeclaredTypeAcceptor acceptor, final boolean isPreIndexingPhase) {
    if (model instanceof SDMakerModel) {
      _infer((SDMakerModel)model, acceptor, isPreIndexingPhase);
      return;
    } else if (model != null) {
      _infer(model, acceptor, isPreIndexingPhase);
      return;
    } else {
      throw new IllegalArgumentException("Unhandled parameter types: " +
        Arrays.<Object>asList(model, acceptor, isPreIndexingPhase).toString());
    }
  }
}
